#include "server.h"
#include "acceptor.h"
#include "reactor.h"
#include "thpool.h"
#include <errno.h>
#include <netdb.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "common.h"

int server_init(int *listenfd, int *epollfd)
{
	struct addrinfo hints;
	struct addrinfo *rp, *result;
	int optval, lfd, efd;

	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	if (getaddrinfo(NULL, PORT_NUM, &hints, &result) != 0)
	{
		outputError(errno, "%s", "getaddrinfo error");
	}

	optval = 1;
	for (rp = result; rp != NULL; rp = rp->ai_next)
	{
		lfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if (lfd == -1)
		{
			continue;
		}

		if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0)
		{
			outputError(errno, "%s", "setsockopt error");
		}

		if (bind(lfd, rp->ai_addr, rp->ai_addrlen) == 0)
		{
			break;
		}

		close(lfd);
	}

	if (rp == NULL)
	{
		outputError(errno, "%s", "could not bind socket to any address");
	}

	if (listen(lfd, BACKLOG) == -1)
	{
		outputError(errno, "%s", "listen error");
	}

	*listenfd = lfd;

	efd = epoll_create(5);
	if (efd == -1)
	{
		outputError(errno, "%s", "epoll_create error");
	}

	*epollfd = efd;

	return 0;
}

int main(int argc, char *argv[])
{
	thpool_t *thpool;
	reactor_t *reactor;
	int listenfd, epollfd;
	event_handler_t *eh;
	acceptor_t *acceptor;
	int ret;
	int i;

	thpool = thpool_init(THREAD_NUM);

	ret = server_init(&listenfd, &epollfd);
	reactor = create_reactor(epollfd, thpool);

	acceptor = create_acceptor(listenfd, reactor);
	reactor->acceptor = acceptor;

	reactor->event_loop(reactor);

	return 0;
}